/**
 * Token管理器 - 基于ai-writer-lite项目的实现
 * 提供准确的token计数和成本计算
 */

// 简化版token计数，如果需要更精确的计数可以安装js-tiktoken
export class TokenManager {
  private static instance: TokenManager

  private constructor() {}

  public static getInstance(): TokenManager {
    if (!TokenManager.instance) {
      TokenManager.instance = new TokenManager()
    }
    return TokenManager.instance
  }

  /**
   * 估算文本的token数量
   * 基于不同语言和大致的token/字符比例
   */
  public countTokens(text: string, model?: string): number {
    if (!text || text.trim().length === 0) {
      return 0
    }

    // 根据模型类型调整计数策略
    if (model?.includes('gpt')) {
      return this.estimateOpenAITokens(text)
    } else if (model?.includes('claude')) {
      return this.estimateClaudeTokens(text)
    } else {
      // 默认使用通用估算
      return this.estimateGenericTokens(text)
    }
  }

  /**
   * 估算消息列表的token数量
   */
  public countMessagesTokens(messages: Array<{role: string; content: string}>, model?: string): number {
    let totalTokens = 0

    for (const message of messages) {
      // 每条消息有一些固定的token开销
      totalTokens += 4 // role, content等字段的开销
      totalTokens += this.countTokens(message.content, model)
    }

    // 添加额外的格式开销
    totalTokens += 3 // 通常的格式开销

    return totalTokens
  }

  /**
   * 计算API调用成本
   */
  public calculateCost(
    promptTokens: number,
    completionTokens: number,
    provider: string,
    model: string
  ): number {
    const rates = this.getPricingRates()
    const rateKey = `${provider}-${model}`

    if (rates[rateKey]) {
      const { promptPrice, completionPrice } = rates[rateKey]
      return (promptTokens * promptPrice) + (completionTokens * completionPrice)
    }

    // 使用默认费率
    const defaultRate = rates[`${provider}-default`]
    if (defaultRate) {
      const { promptPrice, completionPrice } = defaultRate
      return (promptTokens * promptPrice) + (completionTokens * completionPrice)
    }

    return 0
  }

  /**
   * 估算最大回复token数
   */
  public estimateMaxTokens(inputText: string, model: string, maxOutputLength?: number): number {
    const inputTokens = this.countTokens(inputText, model)

    // 不同模型的上下文窗口限制
    const modelLimits: Record<string, number> = {
      'gpt-4': 8192,
      'gpt-4-turbo': 128000,
      'gpt-4o': 128000,
      'gpt-3.5-turbo': 16385,
      'claude-3-opus': 200000,
      'claude-3-sonnet': 200000,
      'claude-3-haiku': 200000,
      'claude-3-5-sonnet-20241022': 200000,
      'deepseek-chat': 32000,
      'deepseek-coder': 16000,
    }

    const contextLimit = modelLimits[model] || 4096

    // 保留一些空间用于系统消息和格式
    const reserveTokens = 1000
    const availableTokens = contextLimit - inputTokens - reserveTokens

    if (maxOutputLength) {
      const maxOutputTokens = this.countTokens(' '.repeat(maxOutputLength), model)
      return Math.min(availableTokens, maxOutputTokens)
    }

    return Math.max(availableTokens, 1000) // 至少保留1000 tokens用于输出
  }

  /**
   * 批量计算token数量
   */
  public batchCountTokens(texts: string[], model?: string): number[] {
    return texts.map(text => this.countTokens(text, model))
  }

  /**
   * 获取token使用统计
   */
  public getTokenUsageStats(usage: {
    promptTokens: number
    completionTokens: number
    totalTokens?: number
  }): {
    promptTokens: number
    completionTokens: number
    totalTokens: number
    promptPercentage: number
    completionPercentage: number
  } {
    const totalTokens = usage.totalTokens || usage.promptTokens + usage.completionTokens

    return {
      promptTokens: usage.promptTokens,
      completionTokens: usage.completionTokens,
      totalTokens,
      promptPercentage: totalTokens > 0 ? (usage.promptTokens / totalTokens) * 100 : 0,
      completionPercentage: totalTokens > 0 ? (usage.completionTokens / totalTokens) * 100 : 0,
    }
  }

  private estimateOpenAITokens(text: string): number {
    // OpenAI模型的token估算
    // 英文大约4个字符 = 1个token
    // 中文大约1.5-2个字符 = 1个token

    const chineseChars = (text.match(/[\u4e00-\u9fff]/g) || []).length
    const englishChars = text.length - chineseChars

    return Math.ceil(chineseChars / 1.5 + englishChars / 4)
  }

  private estimateClaudeTokens(text: string): number {
    // Claude模型的token估算
    // 与OpenAI类似但稍有不同

    const chineseChars = (text.match(/[\u4e00-\u9fff]/g) || []).length
    const englishChars = text.length - chineseChars

    return Math.ceil(chineseChars / 1.4 + englishChars / 3.8)
  }

  private estimateGenericTokens(text: string): number {
    // 通用token估算
    return Math.ceil(text.length / 3.5)
  }

  private getPricingRates(): Record<string, {promptPrice: number; completionPrice: number}> {
    return {
      // OpenAI定价 (每1K tokens的美元价格)
      'openai-gpt-4': { promptPrice: 0.03, completionPrice: 0.06 },
      'openai-gpt-4-turbo': { promptPrice: 0.01, completionPrice: 0.03 },
      'openai-gpt-4o': { promptPrice: 0.005, completionPrice: 0.015 },
      'openai-gpt-3.5-turbo': { promptPrice: 0.0015, completionPrice: 0.002 },
      'openai-default': { promptPrice: 0.01, completionPrice: 0.03 },

      // Anthropic定价
      'anthropic-claude-3-opus': { promptPrice: 0.015, completionPrice: 0.075 },
      'anthropic-claude-3-sonnet': { promptPrice: 0.003, completionPrice: 0.015 },
      'anthropic-claude-3-haiku': { promptPrice: 0.00025, completionPrice: 0.00125 },
      'anthropic-claude-3-5-sonnet-20241022': { promptPrice: 0.003, completionPrice: 0.015 },
      'anthropic-default': { promptPrice: 0.003, completionPrice: 0.015 },

      // DeepSeek定价
      'deepseek-deepseek-chat': { promptPrice: 0.001, completionPrice: 0.002 },
      'deepseek-deepseek-coder': { promptPrice: 0.001, completionPrice: 0.002 },
      'deepseek-default': { promptPrice: 0.001, completionPrice: 0.002 },

      // 本地模型无成本
      'local-default': { promptPrice: 0, completionPrice: 0 },
    }
  }

  /**
   * 格式化token数量为人类可读格式
   */
  public formatTokens(tokens: number): string {
    if (tokens >= 1000000) {
      return `${(tokens / 1000000).toFixed(1)}M`
    } else if (tokens >= 1000) {
      return `${(tokens / 1000).toFixed(1)}K`
    }
    return tokens.toString()
  }

  /**
   * 格式化成本为人类可读格式
   */
  public formatCost(cost: number, currency: string = 'USD'): string {
    return `${currency} $${cost.toFixed(4)}`
  }
}

// 导出单例实例
export const getTokenManager = (): TokenManager => {
  return TokenManager.getInstance()
}